package fox.framework.rpc.endpoint.netty.heartbeat;

import fox.framework.rpc.client.heartbeat.Heartbeat;
import fox.framework.rpc.client.heartbeat.Ping;
import fox.framework.rpc.exception.RpcHeartbeatTimeOutException;
import io.netty.channel.Channel;
import io.netty.channel.ChannelPromise;
import io.netty.handler.timeout.IdleStateEvent;


/**
 * @author cuichao
 * @Description: NettyHeartbeat
 * @Date: create in 2021/2/10 21:24
 */
public class NettyHeartbeat implements Heartbeat<Channel> {

    private Channel channel;

    private int reset = 0;

    private int counter = 0;

    private int maxCounter = 3;

    private Heartbeat heartbeat = this;


    public NettyHeartbeat() {
    }

    public NettyHeartbeat(int maxCounter) {
        this.maxCounter = maxCounter;
    }

    public void trigger(IdleStateEvent event){
        switch (event.state()){
            case ALL_IDLE:
            case READER_IDLE:
            case WRITER_IDLE:
                counter++;
                if(maxCounter > 0 && counter > maxCounter){
                    heartbeat.idle();
                }else{
                    heartbeat.ping();
                }
              break;
            default:
                //nothing to do
        }
    }



    @Override
    public void registry(Channel channel) {
        this.channel = channel;
    }

    @Override
    public void touch() {
        reset();
    }

    @Override
    public void ping() {
        channel.writeAndFlush(new Ping(Ping.PING));
    }

    @Override
    public void pong() {
        reset();
        channel.writeAndFlush(new Ping(Ping.PONG));
    }

    @Override
    public void idle() {
        String msg = String.format("channel:%s remote-address:%s the heartbeat is timeout",channel.id(),channel.remoteAddress());
        ChannelPromise channelPromise = channel.newPromise();
        channelPromise.setFailure(new RpcHeartbeatTimeOutException(msg));
        channel.disconnect();
        channel.close(channelPromise);
    }


    private void reset(){
        this.counter = reset;
    }



}
